declare module 'knex/types/tables' {
    interface User {
        uid: number
        is_admin: boolean
        user_name: string
        name: string
        pwd: string
        tel: string
        email: string
        avatar: string
        gender: string
        signature: string
        hide_name: boolean
        hide_tel: boolean
        hide_class: boolean
        hide_email: boolean
        college_class: string
    }
    interface Tables {
        users: User
    }
}
import {RedisSearchLanguages} from "@redis/search/dist/commands"
import {User} from "knex/types/tables"
import {SchemaFieldTypes} from "redis"
import {redisSQLDatabase} from "TYPE"
import {cache, createIndex, r_} from "../cache"
import knex from '../sql'
import {userPostRelationDB} from "./user_post_relation.db"
import {userRelativeDB} from "./user_relative.db"

class UserDB implements redisSQLDatabase {

    readonly indexName = 'idx:users'

    async getUserById(uid: number, withPassword = false, details = false, all = false) {
        let user_raw: User = await cache.json.get(`user:` + uid) as any
        if (!user_raw) {
            await knex('users').select().where('uid', uid).first().then(u => {
                user_raw = u
                cache.json.set(`user:` + uid, '$', user_raw as any)
            })
        }
        if (all) return user_raw
        let user: any = {}
        let col = ['uid', 'user_name', 'avatar']
        if (details) {
            col = ['uid', 'user_name', 'avatar', 'gender', 'signature']
            for(let v of ['tel','name','email']){
                if(!user_raw['hide_'+v]){
                    col.push(v)
                }
            }
            if(!user_raw['hide_class']) col.push('college_class')
            user['achievement'] = await userPostRelationDB.getAchievementByUid(user_raw.uid)
            user.fans = await userRelativeDB.queryRelativeToByUid(uid, 'follow')
        }
        for (const c of col) {
            user[c] = user_raw[c]
        }
        if (!withPassword && user.pwd) delete user.pwd
        return user
    }
    async updateCache(uid: number) {
        await knex('users').select().where('uid', uid).first().then(u => {
            cache.json.set(`user:` + uid, '$', u as any)
            // cache.bf.add('username_bf', u.user_name)
        })
    }
    async loadAll() {
        await knex('users').select().then(us => {
            // cache.del('username_bf')
            for (let user of us) {
                cache.json.set(`user:` + user.uid, '$', user as any)
                // cache.bf.add('username_bf', user.user_name)
                userPostRelationDB.initAchievement(user.uid)
            }
        })
    }
    async initIndex(del = false) {
        if (del) {
            await cache.ft.dropIndex(this.indexName)
        }
        await createIndex(this.indexName, {
            '$.uid': {
                type: SchemaFieldTypes.NUMERIC as any,// bug
                SORTABLE: true,
                AS: 'uid'
            },
            '$.user_name': {
                type: SchemaFieldTypes.TEXT,
                AS: 'user_name'
            },
            '$.user_name ': { // Also index username as tag, same with email.
                type: SchemaFieldTypes.TAG,
                // SORTABLE: 'UNF',
                AS: 'user_name_tag'
            },
            '$.email': {
                type: SchemaFieldTypes.TEXT,
                AS: 'email'
            },
            '$.email ': {
                type: SchemaFieldTypes.TAG,
                AS: 'email_tag'
            },
            '$.name': {
                type: SchemaFieldTypes.TEXT,
                // SORTABLE: 'UNF',
                AS: 'name'
            },
            '$.tel': {
                type: SchemaFieldTypes.TEXT,
                NOSTEM: true,// 不分词
                AS: 'tel'
            },
            '$.gender': {
                type: SchemaFieldTypes.TAG,
                AS: 'gender'
            }
        }, {
            ON: 'JSON', PREFIX: 'user:', LANGUAGE: RedisSearchLanguages.CHINESE
        })
    }
    async emailExists(email: string) {
        let key = `emailExsit:` + email
        let v = await cache.get(key)
        if (v == 'no')
            return null
        if (v) {
            return await this.getUserById(Number(v), true)
        }

        let user = await cache.ft.search(this.indexName, `@email_tag:{${r_(email)}}`)

        if (user.total) {
            cache.setEx(key, 10, user.documents[0].value.uid + '')
            return user.documents[0].value
        }
        else
            cache.setEx(key, 10, 'no')
        return null
    }
    async nameExists(username: string) {
        // let user: User
        // if (! await cache.bf.exists('username_bf', username)) {
        //     return null
        // }
        let v = await cache.get(`nameExsit:` + username)
        if (v == 'no')
            return null
        if (v) {
            return await this.getUserById(Number(v), true)
        }
        let user = await cache.ft.search(this.indexName, `@user_name_tag:{${r_(username)}}`)

        if (user.total) {
            cache.setEx(`nameExsit:` + username, 10, user.documents[0].value.uid + '')
            return user.documents[0].value
        }
        else
            cache.setEx(`nameExsit:` + username, 10, 'no')
        return null
    }
}
export const userDB = new UserDB()

